let genCounter = 0

// 生成 Widget ID
export function genWidgetId (prefix: string) {
  const customPrefix = prefix ? prefix + '_' : ''
  const randPostfix = `${+new Date()}_${genCounter++}`
  return `${customPrefix}${randPostfix}`
}

type Position = {
  x: number,
  y: number,
  w: number,
  h: number,
}

export class LayoutEngine {
  cachePositions: Position[] = []

  constructor (positions?: Position[]) {
    if (positions) {
      this.cachePositions = positions
    }
  }

  _getAllPositions (positions: Position[], cache?: boolean) {
    if (cache) {
      window.requestAnimationFrame(() => {
        this.cachePositions = []
      })
    }
    return positions.concat(this.cachePositions).map(e => {
      return {
        x: e.x,
        y: e.y,
        w: e.w,
        h: e.h
      }
    })
  }

  _checkCollide (pos1: Position, pos2: Position) {
    let isCollide = true
    if (pos1 === pos2) isCollide = false
    if (pos1.x + pos1.w <= pos2.x) isCollide = false
    if (pos1.x >= pos2.x + pos2.w) isCollide = false
    if (pos1.y + pos1.h <= pos2.y) isCollide = false
    if (pos1.y >= pos2.y + pos2.h) isCollide = false
    return isCollide
  }

  getNextPos (w: number, h: number, {
    positions,
    cache,
    column
  }: {
    positions?: Position[],
    cache?: boolean,
    column?: number,
  }) {
    // 默认参数值
    positions = positions || []
    column = column || 10

    const allPositions = this._getAllPositions(positions, cache)

    let maxPos = allPositions[0] || {
      x: 0,
      y: 0,
      w: 0,
      h: 0
    }
    allPositions.forEach(e => {
      if (e.y + e.h < maxPos.y + maxPos.h) return
      if (e.y + e.h > maxPos.y + maxPos.h ||
        e.x + e.w > maxPos.x + maxPos.w) {
        maxPos = e
      }
    })

    const position: Position = {
      x: 0,
      y: 0,
      w: 0,
      h: 0
    }
    if (maxPos.x + maxPos.w <= column - w) {
      position.x = maxPos.x + maxPos.w
      position.y = maxPos.y
    } else {
      position.x = 0
      position.y = maxPos.y + 1
    }
    position.w = w
    position.h = h
    this.cachePositions.push(position)
    return position
  }

  getSpacePos (w: number, h: number, {
    positions,
    cache,
    column,
    row
  }: {
    positions?: Position[],
    cache?: boolean,
    column?: number,
    row?: number,
  }): Position {
    // 默认参数值
    positions = positions || []
    column = column || 10
    row = row || 999
    cache = cache || true

    const allPositions = this._getAllPositions(positions, cache)
    const fakePos = {
      w: w,
      h: h,
      x: 0,
      y: 0
    }
    let hasSpace
    do {
      hasSpace = true
      for (const pos of allPositions) {
        if (this._checkCollide(pos, fakePos)) {
          hasSpace = false
          break
        }
      }
      if (!hasSpace) {
        if (fakePos.x + 1 + w <= column) {
          fakePos.x++
        } else {
          fakePos.x = 0
          fakePos.y++
        }
      }
      if (fakePos.y + h > row) {
        hasSpace = false
        break
      }
    } while (!hasSpace)

    // console.log('getSpacePos', hasSpace ? fakePos : null);

    if (hasSpace) {
      cache && this.cachePositions.push(fakePos)
      return fakePos
    }
    return fakePos
  }

  clearCache () {
    this.cachePositions = []
  }
}

// 实例化一个全局 Engine
const layoutEngine = new LayoutEngine([])
export const getNextWidgetPos = layoutEngine.getSpacePos.bind(layoutEngine)

type ObjectArrayWithId = { id: string | number }[];

export function diffArrayById (newItems: ObjectArrayWithId, oldItems: ObjectArrayWithId) {
  const appends = newItems.filter(e => !oldItems.find(j => j.id === e.id))
  const removes = oldItems.filter(e => !newItems.find(j => j.id === e.id))
  const retains = newItems.filter(e => !appends.find(j => j.id === e.id))
  return {
    appends,
    removes,
    retains
  }
}
